<?php

declare(strict_types=1);

namespace App\Chat\Controller;

use App\Chat\Cache\SocketRoom;
use App\Chat\Constant\TalkEventConstant;
use App\Chat\Event\TalkEvent;
use App\Chat\Service\GroupMemberService;
use App\Chat\Service\Message\ReceiveHandleService;
use App\Chat\Service\SocketClientService;
use App\Chat\Ws\Contact\ISender;
use App\Chat\Ws\Contact\ISocketClientService;
use App\CustHub\Service\ChCustomerServiceService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Contract\OnCloseInterface;
use Hyperf\Contract\OnMessageInterface;
use Hyperf\Contract\OnOpenInterface;
use Psr\Http\Message\ServerRequestInterface;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;


/**
 * Class WebSocketController
 *
 * @package App\Controller
 */
class WebSocketController implements OnMessageInterface, OnOpenInterface, OnCloseInterface
{
    #[Inject]
    protected SocketClientService $client;

    #[Inject]
    protected ReceiveHandleService $receiveHandle;

    #[Inject]
    protected ChCustomerServiceService $customerService;

    /**
     * @var ISocketClientService
     */
    #[Inject]
    protected ISocketClientService $socketClientService;

    /**
     *
     * @var ISender
     */
    #[Inject]
    protected ISender $sender;

    /**
     * 连接创建成功回调事件
     *
     * @param Response|Server $server
     * @param Request         $request
     */
    public function onOpen($server, $request): void
    {
        $server->push($request->fd, json_encode([
            "event"   => "connect",
            "content" => [
                "ping_interval" => 20,
                "ping_timeout"  => 20 * 3,
            ],
        ]));

        // 当前连接的用户
        $user_id = chatUser()->getUserInfo( container()->get(ServerRequestInterface::class)->getQueryParams()['token'])['id'];

        stdout_log()->notice("用户连接信息 : user_id:{$user_id} | fd:{$request->fd} 时间：" . date('Y-m-d H:i:s'));

        // 判断是否存在异地登录
        $isOnline = $this->client->isOnlineAll($user_id);

        // 绑定fd与用户关系
//        $this->client->bind($request->fd, $user_id);
        $this->socketClientService->bindRelation($request->fd, $user_id);

        // 更新用户在线状态
        $this->customerService->changeOnlineStatus($user_id, 1);

        // 加入群聊
//        $groupIds = di()->get(GroupMemberService::class)->getUserGroupIds($user_id);
//        foreach ($groupIds as $group_id) {
//            SocketRoom::getInstance()->addRoomMember(strval($group_id), strval($user_id));
//        }
        if (!$isOnline) {
            event(new TalkEvent(TalkEventConstant::EVENT_LOGIN, [
                'user_id' => $user_id,
                'status'  => 1,
            ]));
        }
    }

    /**
     * 消息接收回调事件
     *
     * @param Response|Server $server
     * @param Frame           $frame
     */
    public function onMessage($server, $frame): void
    {
        $result = json_decode($frame->data, true);
        // 判断是否为心跳检测
        if ($result['event'] == 'heartbeat') {
            $server->push($frame->fd, json_encode(['event' => "heartbeat", 'content' => "pong"]));
            return;
        }
        if (!isset(ReceiveHandleService::EVENTS[$result['event']])) {
            return;
        }
        // 回调处理
        call_user_func_array([$this->receiveHandle, ReceiveHandleService::EVENTS[$result['event']]], [
            $server, $frame, $result['data']
        ]);
    }

    /**
     * 连接关闭回调事件
     *
     * @param Response|\Swoole\Server $server
     * @param int                     $fd
     * @param int                     $reactorId
     */
    public function onClose($server, int $fd, int $reactorId): void
    {
        $user_id = $this->socketClientService->findFdUserId($this->socketClientService->genDistributeFd($fd)->toString());

        stdout_log()->notice("客户端FD:{$fd} 已关闭连接 ，用户ID为【{$user_id}】，关闭时间：" . date('Y-m-d H:i:s'));

        // 删除 fd 绑定关系
//        $this->client->unbind($fd);
        $this->socketClientService->removeRelation($this->socketClientService->genDistributeFd($fd)->toString());

        // 更新用户在线状态
        $this->customerService->changeOnlineStatus($user_id, 0);

        // 判断是否存在异地登录
        $isOnline = $this->client->isOnlineAll($user_id);
        if ($isOnline) return;

        event(new TalkEvent(TalkEventConstant::EVENT_LOGIN, [
            'user_id' => $user_id,
            'status'  => 0,
        ]));
    }
}